﻿// Chuyen cac ReadTickets, ReadWells, ..v..v.. thanh Non Static het.
// Hien co 2 cach doc cac Property : Update cac gia tri vao object C#, sau do dung timer lau lau moi check lai 1 lan (tiet kiem thoi gian neu cu phai ghi hoai)
//                                   Update truc tiep vua vao cac object C#, vua vao file config luon (cai nay thi khong co gi phai lo lang)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace DienLib.ReportLib
{
    public class ELUnit
    {
        public string UnitName { get; set; }
        public List<string> PowerPack { get; set; }
        public List<string> WinchFrame { get; set; }
        public List<string> CabinUnit { get; set; }
        public List<string> CableDrum { get; set; }
        public List<string> DrumRack { get; set; }
        public List<string> Mast { get; set; }
        public List<string> MastPowerPack { get; set; }
        public List<string> MVDHSVPump { get; set; }
        public List<string> DogHouse { get; set; }
        public List<string> PCEMainFrame { get; set; }
        public List<string> BOPCage { get; set; }
        public List<string> AirComp { get; set; }
        public List<string> DrumCarrier { get; set; }
        public List<string> GunBox { get; set; }
        public List<string> RigUpBox { get; set; }
        public List<string> Other { get; set; }
        public DateTime LastUpdate { get; set; }

        public ELUnit(string unitName)
        {
            UnitName = unitName; LastUpdate = DateTime.MinValue;
            initList();
        }

        private void initList()
        {
            PowerPack = new List<string>();
            WinchFrame = new List<string>();
            CabinUnit = new List<string>();
            CableDrum = new List<string>();
            DrumRack = new List<string>();
            Mast = new List<string>();
            MastPowerPack = new List<string>();
            MVDHSVPump = new List<string>();
            DogHouse = new List<string>();
            PCEMainFrame = new List<string>();
            BOPCage = new List<string>();
            AirComp = new List<string>();
            GunBox = new List<string>();
            RigUpBox = new List<string>();
            Other = new List<string>();
        }
    }

    public class Well
    {
        public string Name { get; set; }
        public string Rig_Platform { get; set; }
        public string Field { get; set; }
        public string HoleType { get; set; }
        public double DrillDepth { get; set; }
        public double LastHUD { get; set; }
        public double TubingSize { get; set; }
        public double TubingShoe { get; set; }
        public double CasingSize { get; set; }
        public double CasingShoe { get; set; }
        public double EstimatedTOC { get; set; }
        public double CBL_TOC { get; set; }
        public double MaxBHT { get; set; }
        public double WHP { get; set; }
        public string WellFluid { get; set; }
        public double FluidChangeDepth { get; set; }
        public string Gravity { get; set; }
        public double FluidLevel { get; set; }
        public double BitSize { get; set; }
        public double MinID { get; set; }
        public double MinID_Depth { get; set; }
        public double MaxDEV { get; set; }
        public double MaxDEV_Depth { get; set; }
        public double KOP { get; set; }
        public double KOP_Depth { get; set; }
        public double MaxDLR { get; set; }
        public double MaxDLR_Depth { get; set; }
        public double DevTD { get; set; }
        public double DirTD { get; set; }
        public string GammaLogName { get; set; }
        public DateTime GammaLogDate { get; set; }
        public string CCLLogName { get; set; }
        public DateTime CCLLogDate { get; set; }
        public DateTime LastUpdate { get; set; }

        public string ShipTo { get; set; }

        public Well(string wellName)
        {
            Name = wellName;
        }
    }

    public class JobType
    {
        public string ShortName { get; set; }
        public string FarpacName { get; set; }
        public JobType(string shortName, string farpacname)
        {
            ShortName = shortName;
            FarpacName = farpacname;
        }
    }

    public class ShipTo
    {
        public string WellName { get; set; }
        public string Ship2Number { get; set; }

        public ShipTo(string wellName, string ship2Number)
        {
            WellName = wellName;
            Ship2Number = ship2Number;
        }

        public override string ToString()
        {
            return Ship2Number;
        }
    }

    public class Ticket
    {
        public string Number { get; set; }
        public string WellName { get; set; }
        public string JobType { get; set; }
        public DateTime OpenDate { get; set; }
        public string OpenEngineer { get; set; }
        public string ClosedEngineer { get; set; }
        public DateTime ClosedDate { get; set; }
        public double JobMD { get; set; }
        public double JobTVD { get; set; }
        public List<string> ToolsUsed { get; set; }

        public Ticket(string number)
        {
            Number = number;
            ToolsUsed = new List<string>();
        }

        public override string ToString()
        {
            /*if (Regex.IsMatch(WellName, "[a-zA-Z0-9]")) return Number + " : " + WellName;
            else*/
            return Number;
        }
    }

    public class CableDrum
    {
        public CableDrum(string drumSerial, string cableSerial, string cableType, double totalLength, int totalRuns, DateTime lastUpdated)
        {
            DrumSerial = drumSerial;
            CableSerial = cableSerial;
            CableType = cableType;
            TotalLength = totalLength;
            TotalRuns = totalRuns;
            LastUpdated = lastUpdated;

            Item i = new Item(LastUpdated, TotalRuns, TotalLength);
            DailyUse = new List<Item>(); DailyUse.Add(i);
        }

        public string DrumSerial { get; private set; }
        public string CableSerial { get; private set; }
        public string CableType { get; private set; }
        public double TotalLength { get; private set; }
        public int TotalRuns { get; private set; }
        public DateTime LastUpdated { get; private set; }

        public List<Item> DailyUse { get; set; }

        public struct Item
        {
            public Item(DateTime date, int totalRun, double balancelength)
                : this()
            {   // Constructor nay duoc goi khi nao can tao mot Item doc tu Config File
                Date = date;
                TotalRunLine = totalRun;
                BalanceLength = balancelength;
            }
            public DateTime Date { get; set; }
            public string Ticket { get; set; }
            public string Service { get; set; }
            public string WellName { get; set; }
            public double WellAngle { get; set; }
            public double TubingSize { get; set; }
            public string WellFluid { get; set; }
            public double WHP { get; set; }
            public string H2S { get; set; }
            public string CO2 { get; set; }
            public double BHT { get; set; }
            public double MaxDepth { get; set; }
            public double MaxTension { get; set; }
            public double MinTension { get; set; }
            public int RunOnJob { get; set; }
            public int TotalRunLine { get; set; }
            public int TotalRunWP { get; set; }
            public double CableCut { get; set; }
            public string ReasonCut { get; set; }
            public double BalanceLength { get; set; }
            public double WeakPoint { get; set; }
            public string OutInArmour { get; set; }
            public double FlowTubeSize { get; set; }
            public int NumberFlowTube { get; set; }
            public int RunOnFlowTube { get; set; }
            public string CableMicDepth { get; set; }
            public string TwistTest { get; set; }
            public double Resistance { get; set; }
            public string Engineer { get; set; }
            public string Comment { get; set; }
        }
    }

    public class Configuration
    {
        #region ENUM PATH
        public enum Paths
        {   // Enum Name must start with FOLDER_ or FILE_ prefix to make sure can seperate FILE / FOLDER Paths
            NA,
            // if you ADD or CHANGE here. Need to Modify config.xlsx sheet "Path" as is. Otherwise things will not work as you expected. 
            // Also change in EnumFolderPaths(). Consider to not use FOLDER PATH for file that have FILE PATH already. because they are the same, duplicate & can get from FILE_PATH
            //  1. Add Column Enum in config.xlsx (same name with here)
            //  2. Modify Column Pattern in config.xlsx
            //  3. Add EnumFolderPaths() for correct Value
            //  4. Add Event for button with correct Paths.
            //  5. Add Context Menu for button with correct Paths.

            
            FOLDER_OPERATION_InUse,
            FOLDER_OPERATION_BackUp,
            FOLDER_CableRecord,
            FOLDER_CCLTracking,
            FOLDER_CHMaintenance,
            FOLDER_Checklist,
            FOLDER_DailyReport,
            FOLDER_Explosive,
            FOLDER_FARPAC,
            FOLDER_HazardHunt,
            FOLDER_HOC,
            FOLDER_PCE,
            FOLDER_PerfPlan,
            FOLDER_Chopper,

            FOLDER_JSA,
            FOLDER_HMS,
            FOLDER_WorkMethod,
            FOLDER_LOGIQ,
            FOLDER_MultiSplit,
            FOLDER_Icon,
            //============ FILE =============//
            FILE_CableRecord,
            FILE_CCLTracking,
            FILE_CHMaintenance,

            //FILE_Checklist_RMPC,

            FILE_DailyReport,
            FILE_Explosive,
            FILE_FARPAC_Sample,
            FILE_FARPACS,
            FILE_HazardHunt,
            FILE_HOC,
            FILE_PCE,
            FILE_PerfPlan,
            FILE_PerfRisk,
            FILE_Chopper,

            FILE_Poster
        }
        const int PATHCOLUMN = 2;
        const int ENUMCOLUMN = 1;
        const int PATTERNCOLUMN = 3;

        static Configuration()
        {
            PathsFile = GetFilePathsCollection();
            PathsFolder = GetFolderPathsCollection();
        }

        public static Paths[] PathsFile { get; private set; }
        public static Paths[] PathsFolder { get; private set; }

        private static Paths[] GetFolderPathsCollection()
        {
            List<Paths> list = new List<Paths>();
            foreach (Paths path in Enum.GetValues(typeof(Paths)))
            {
                if (path.ToString().ToLower().StartsWith("folder_")) list.Add(path);
            }
            return list.ToArray();
        }
        private static Paths[] GetFilePathsCollection()
        {
            List<Paths> list = new List<Paths>();
            foreach (Paths path in Enum.GetValues(typeof(Paths)))
            {
                if (path.ToString().ToLower().StartsWith("file_")) list.Add(path);
            }
            return list.ToArray();
        }

        public static Paths EnumFolderPaths(Paths fromFilePaths)
        {
            switch (fromFilePaths)
            {
                case Paths.FILE_CableRecord: return Paths.FOLDER_CableRecord;
                case Paths.FILE_CCLTracking: return Paths.FOLDER_CCLTracking;
                case Paths.FILE_CHMaintenance: return Paths.FOLDER_CHMaintenance;
                case Paths.FILE_DailyReport: return Paths.FOLDER_DailyReport;
                case Paths.FILE_Explosive: return Paths.FOLDER_Explosive;
                case Paths.FILE_FARPAC_Sample: return Paths.FOLDER_FARPAC;
                case Paths.FILE_FARPACS: return Paths.FOLDER_FARPAC;
                case Paths.FILE_HazardHunt: return Paths.FOLDER_HazardHunt;
                case Paths.FILE_HOC: return Paths.FOLDER_HOC;
                case Paths.FILE_PCE: return Paths.FOLDER_PCE;
                case Paths.FILE_PerfPlan: return Paths.FOLDER_PerfPlan;
                case Paths.FILE_PerfRisk: return Paths.FOLDER_PerfPlan;
                case Paths.FILE_Chopper: return Paths.FOLDER_Chopper;
                default: throw new InvalidOperationException("GetFolderPaths FAIL due to no FOLDER PATH from this File Path : " + fromFilePaths.ToString());
            }
        }
        public static bool IsFolderPaths(Paths path)
        {
            return path.ToString().ToLower().StartsWith("folder_");
        }
        public static bool IsFilePaths(Paths path)
        {
            return path.ToString().ToLower().StartsWith("file_");
        }

        #endregion

        #region BASIC READ WRITE PATTERN for PATH
        /// <summary>
        /// Get Full Path directly from config.xlsx file
        /// </summary>
        /// <param name="pathtype">PathType you want to get Full Path</param>
        /// <param name="closethen">Close the config after read or not</param>
        /// <returns></returns>
        private string PathRead(Paths pathType, bool closethen = true)
        {
            string s = null;

            PathDo(pathType, row =>
            {
                s = g_xls.ReadCell<string>(row, PATHCOLUMN);
                if (s.StartsWith(" ") | s.EndsWith(" "))
                {
                    DienLib.PopUp.PopUpResult res = DienLib.PopUp.PopUpOKCancel.ShowDialog(string.Format("Found useless SPACE of PATH in R{0}C{1}, sheet Path of Config.xlsx : \"{2}\"\r\n" +
                    "I will replace those useless space for you now. Click OK to continue ...", row, PATHCOLUMN.ToString(), s), "SPACE at BEGIN or END of PATH");
                    s = s.Trim(); if (res == DienLib.PopUp.PopUpResult.OK) g_xls.WriteCell<string>(row, PATHCOLUMN, s);
                }
            }, closethen);

            return s;
        }

        /// <summary>
        /// Write Full Path directly to Config.xlsx file
        /// </summary>
        /// <param name="pathtype">PathType you want to write to</param>
        /// <param name="closethen">will close</param>
        /// <returns>true if success</returns>
        private bool PathWrite(Paths pathType, string value, bool closethen = true)
        {
            bool b = false;

            PathDo(pathType, row =>
            {
                g_xls.WriteCell<string>(row, PATHCOLUMN, value);
                b = true;
            }, closethen, true);

            return b;
        }

        /// <summary>
        /// Get Full Path directly from config.xlsx for lots of Path Types at once.
        /// </summary>
        /// <param name="pathTypes">Array of PathType</param>
        /// <returns>a Dict for easy to use</returns>
        private Dictionary<Paths, string> PathRead(Paths[] pathTypes, bool closethen = true)
        {   // return Empty Dict if NOTHING found
            Dictionary<Paths, string> dict = new Dictionary<Paths, string>();

            PathDo(pathTypes, (row, index) => // Lamda Expression
            {
                string s = g_xls.ReadCell<string>(row, PATHCOLUMN);
                if (s.StartsWith(" ") | s.EndsWith(" "))
                {
                    DienLib.PopUp.PopUpResult res = DienLib.PopUp.PopUpOKCancel.ShowDialog(string.Format("Found useless SPACE of PATH in R{0}C{1}, sheet Path of Config.xlsx : \"{2}\"\r\n" +
                    "I will replace those useless space for you now. Click OK to continue ...", row, PATHCOLUMN.ToString(), s), "SPACE at BEGIN or END of PATH");
                    s = s.Trim(); if (res == DienLib.PopUp.PopUpResult.OK) g_xls.WriteCell<string>(row, PATHCOLUMN, s);
                }
                dict.Add(pathTypes[index], s); // IMPLEMENT DUPLICATE VALUE FOUND for ONE KEY
            }, closethen);

            return dict;
        }

        /// <summary>
        /// Write Multiple Paths dỉrectly to Config.xls file at once.
        /// </summary>
        /// <param name="pathTypes">Array of PathType</param>
        /// <param name="values">Array of Value to Write</param>
        /// <param name="closethen">Whether or Not close the xls after Write</param>
        /// <returns>Write Success Dictionary. If true mean that PathTypes Write Success</returns>
        private Dictionary<Paths, bool> PathWrite(Paths[] pathTypes, string[] values, bool closethen = true)
        {   // <returns>-1 success else FAIL at number in array. IMPLEMENT LATER</returns>
            if (pathTypes.Length != values.Length) throw new InvalidOperationException("PathType & Value Array different Length !");

            Dictionary<Paths, bool> dict = new Dictionary<Paths, bool>();
            foreach (Paths path in pathTypes) { dict.Add(path, false); }

            PathDo(pathTypes, (row, index) =>
            {
                g_xls.WriteCell<string>(row, PATHCOLUMN, values[index]);
                dict[pathTypes[index]] = true; // Write sucess for that pathTypes
            }, closethen, true);

            return dict;

            /*if (pathTypes.Length != values.Length) throw new InvalidOperationException("PathType & Value Array different Length !");

            if (g_xls == null) g_xls = new OfficeLib.Excel();
            g_xls.InitBook(FullPath, "", false);

            g_xls.ActivateSheet("Path");
            int iRow = 0, iBlank = 0;
            while (iBlank < 5) // Khi nao Blank tren 5 row lien tiep thi Quit Loop
            {
                //iRow++;
                // Neu Blank thi cu tang iBlank
                if (g_xls.IsBlankCell(++iRow, 1)) iBlank++;
                else
                {
                    iBlank = 0; // Neu co chu thi Reset iBlank bat dau dem lai
                    // Doc Name & So sanh coi trung voi thang nao trong Array
                    string lname = g_xls.ReadCell<string>(iRow, 1).ToLower();
                    foreach (Paths epath in pathTypes)
                    {
                        if (Regex.IsMatch(lname, PathsArr[(int)epath]))
                        {   // Neu Name match voi ePath do thi Write
                            g_xls.WriteCell<string>(iRow, 2, values[(int)epath]);
                        }
                    }
                }
            }

            g_xls.SaveBook();
            if (closethen) { g_xls.CloseBook(); g_xls = null; }*/
        }

        /// <summary>
        /// Get Regex Path Pattern directly from config.xlsx. Eg : "daily.*(report|rpt).*\.xls" for a daily report file. daily.*(report|rpt) for a daily report folder
        /// </summary>
        /// <param name="pathType">PathType you want to write to</param>
        /// <param name="closethen">Close the config after read or not</param>
        /// <returns></returns>
        private string PathPatternRead(Paths pathType, bool closethen = true)
        {
            string s = null;

            PathDo(pathType, row =>
            {
                s = g_xls.ReadCell<string>(row, PATTERNCOLUMN);
                if (s.StartsWith(" ") | s.EndsWith(" "))
                {
                    DienLib.PopUp.PopUpResult res = DienLib.PopUp.PopUpOKCancel.ShowDialog(string.Format("Found useless SPACE of PATTERN in R{0}C{1}, sheet Path of Config.xlsx : \"{2}\"\r\n" +
                    "I will replace those useless space for you now. Click OK to continue ...", row, PATTERNCOLUMN.ToString(), s), "SPACE at BEGIN or END of PATTERN");
                    s = s.Trim(); if (res == DienLib.PopUp.PopUpResult.OK) g_xls.WriteCell<string>(row, PATTERNCOLUMN, s);
                }
            }, closethen);

            return s;
        }

        /// <summary>
        /// Get Regex Path Pattern directly from config.xlsx for Multiple Path Types at once.
        /// </summary>
        /// <param name="pathTypes"></param>
        /// <param name="closethen"></param>
        /// <returns></returns>
        private Dictionary<Paths, string> PathPatternRead(Paths[] pathTypes, bool closethen = true)
        {   // return Empty Dict if NOTHING found
            Dictionary<Paths, string> dict = new Dictionary<Paths, string>();

            PathDo(pathTypes, (row, index) => // Lamda Expression
            {
                string s = g_xls.ReadCell<string>(row, PATTERNCOLUMN);
                if (s.StartsWith(" ") | s.EndsWith(" "))
                {
                    DienLib.PopUp.PopUpResult res = DienLib.PopUp.PopUpOKCancel.ShowDialog(string.Format("Found useless SPACE of PATTERN in R{0}C{1}, sheet Path of Config.xlsx : \"{2}\"\r\n" +
                    "I will replace those useless space for you now. Click OK to continue ...", row, PATTERNCOLUMN.ToString(), s), "SPACE at BEGIN or END of PATTERN");
                    s = s.Trim(); if (res == DienLib.PopUp.PopUpResult.OK) g_xls.WriteCell<string>(row, PATTERNCOLUMN, s);
                }
                dict.Add(pathTypes[index], s); // IMPLEMENT DUPLICATE VALUE FOUND for ONE KEY
            }, closethen);

            return dict;
        }

        /// <summary>
        /// Write Path's Pattern directly to Config.xlsx file
        /// </summary>
        /// <param name="pathType">Path Type to write</param>
        /// <param name="value">Pattern to write to. Eg: daily.*(report|rpt) for a daily report folder</param>
        /// <param name="closethen">Close the config after read or not</param>
        /// <returns></returns>
        private bool PathPatternWrite(Paths pathType, string value, bool closethen = true)
        {
            bool b = false;

            PathDo(pathType, row =>
            {
                g_xls.WriteCell<string>(row, PATTERNCOLUMN, value);
                g_xls.SaveBook();
                b = true;
            }, closethen, true);

            return b;
        }
        //====================================================================================================================================================================================//

        /// <summary>
        /// Base Path ToDo Method for PathRead|Write|Pattern implementation.
        /// </summary>
        /// <param name="pathType"></param>
        /// <param name="ToDo">Better use Lamda Expression to path delegate function</param>
        /// <param name="closethen">Close the config after read or not</param>
        /// <returns>Value Read</returns>
        private void PathDo(Paths pathType, Action<int> ToDo, bool closethen = true, bool save = false)
        {
            if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            g_xls.InitBook(FullPath, "Path", g_xls.ReadCellSilent);

            int iRow = 0, iBlank = 0;
            while (iBlank < 5) // Khi nao Blank tren 5 row lien tiep thi Quit Loop
            {
                // iRow++;
                // Neu Blank thi cu tang iBlank
                if (g_xls.IsBlankCell(++iRow, ENUMCOLUMN)) iBlank++;
                else
                {
                    iBlank = 0; // Neu co chu thi Reset iBlank bat dau dem lai
                    // Doc Name
                    string name = g_xls.ReadCell<string>(iRow, ENUMCOLUMN); // Khong Trim() neu nhap file Excel du ky tu space thi may se bao loi.
                    if (name.StartsWith(" ") | name.EndsWith(" "))
                    {
                        DienLib.PopUp.PopUpResult res = DienLib.PopUp.PopUpOKCancel.ShowDialog(string.Format("Found useless SPACE of ENUM in R{0}C{1}, sheet Path of Config.xlsx : \"{2}\"\r\n" +
                        "I will replace those useless space for you now. Click OK to continue ...", iRow.ToString(), ENUMCOLUMN.ToString(), name), "SPACE at BEGIN or END of ENUM");
                        name = name.Trim(); if (res == DienLib.PopUp.PopUpResult.OK) g_xls.WriteCell<string>(iRow, ENUMCOLUMN, name);
                    }
                    if (name == pathType.ToString())
                    {   // Neu Name match voi PathType thi Read
                        ToDo(iRow);
                    }
                }
            }

            if (save) g_xls.SaveBook();
            if (closethen) { g_xls.CloseBook(); g_xls = null; }
        }

        /// <summary>
        /// Base Path ToDo Multiple Method for PathRead|Write|Pattern implementation.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pathType"></param>
        /// <param name="ToDo">Use Lamda to shorter statement</param>
        /// <param name="closethen"></param>
        /// <returns></returns>
        private void PathDo(Paths[] pathTypes, Action<int, int> ToDo, bool closethen = true, bool save = false)
        {
            if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            g_xls.InitBook(FullPath, "Path", g_xls.ReadCellSilent);

            int iRow = 0, iBlank = 0;
            while (iBlank < 5) // Khi nao Blank tren 5 row lien tiep thi Quit Loop
            {
                // iRow++;
                // Neu Blank thi cu tang iBlank
                if (g_xls.IsBlankCell(++iRow, ENUMCOLUMN)) iBlank++;
                else
                {
                    iBlank = 0; // Neu co chu thi Reset iBlank bat dau dem lai
                    // Doc Name
                    string name = g_xls.ReadCell<string>(iRow, ENUMCOLUMN); // Khong Trim() neu nhap file Excel du ky tu space thi may se bao loi.
                    if (name.StartsWith(" ") | name.EndsWith(" "))
                    {
                        DienLib.PopUp.PopUpResult res = DienLib.PopUp.PopUpOKCancel.ShowDialog(string.Format("Found useless SPACE of ENUM in R{0}C{1}, sheet Path of Config.xlsx : \"{2}\"\r\n" +
                        "I will replace those useless space for you now. Click OK to continue ...", iRow.ToString(), ENUMCOLUMN.ToString(), name), "SPACE at BEGIN or END of ENUM");
                        name = name.Trim(); if (res == DienLib.PopUp.PopUpResult.OK) g_xls.WriteCell<string>(iRow, ENUMCOLUMN, name);
                    }
                    for (int index = 0; index < pathTypes.Length; index++)
                    {
                        if (name == pathTypes[index].ToString())
                        {   // Neu Name match voi PathType thi Read
                            ToDo(iRow, index);
                        }
                    }
                }
            }

            if (save) g_xls.SaveBook();
            if (closethen) { g_xls.CloseBook(); g_xls = null; }
        }

        #endregion

        #region METHOD READ when INIT CONFIG
        /// <summary>
        /// Read Paths when INIT
        /// </summary>
        /// <param name="closethen"></param>
        private void ReadPaths(bool closethen = true)
        {
            if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            g_xls.InitBook(FullPath, "Path", g_xls.ReadCellSilent); // If book already open then Init Sheet only

            Paths[] paths = Enum.GetValues(typeof(Paths)) as Paths[];
            g_PathDict = PathRead(paths, closethen); // Old PathDict already gone.
        }

        /// <summary>
        /// Read Path's Pattern when INIT
        /// </summary>
        /// <param name="closethen"></param>
        private void ReadPathPatterns(bool closethen = true)
        {
            if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            g_xls.InitBook(FullPath, "Path", g_xls.ReadCellSilent); // If book already open then Init Sheet only

            Paths[] paths = Enum.GetValues(typeof(Paths)) as Paths[];
            g_PathPatternDict = PathPatternRead(paths, closethen); // Old PathDict already gone.
        }

        /// <summary>
        /// Read Both Paths & Pattern when INIT
        /// </summary>
        /// <param name="closethen"></param>
        private void ReadPaths_n_Patterns(bool closethen = true)
        {
            if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            g_xls.InitBook(FullPath, "Path", g_xls.ReadCellSilent); // If book already open then Init Sheet only

            Paths[] paths = Enum.GetValues(typeof(Paths)) as Paths[];
            g_PathDict = PathRead(paths, closethen); // Read File & Folder Path. Old PathDict already gone. Eg : Dialy Report : C:\1.OPERATION - in use\Daily Report
            g_PathPatternDict = PathPatternRead(paths, closethen); // Read File & Folder Search Pattern. Old PathPatternDict already gone. Eg : Dialy Report : @"dialy|(report|rpt)"
        }

        private List<CableDrum> ReadCableDrums(bool closethen = true)
        {
            //if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            //g_xls.InitBook(FullPath, "CableDrum", false); // If book already open then Init Sheet only

            List<CableDrum> list = new List<CableDrum>();
            g_xls.ActivateSheet("CableDrum");
            int iRow = 0, iBlank = 0;
            while (iBlank < 5) // Khi nao Blank tren 5 row lien tiep thi Quit Loop
            {
                //iRow++;
                // Neu Blank thi cu tang iBlank
                if (g_xls.IsBlankCell(++iRow, 1)) iBlank++;
                else
                {
                    iBlank = 0; // Neu co chu thi Reset iBlank bat dau dem lai
                    if (g_xls.ReadCell<string>(iRow, 1) == "Drum Serial")
                    {   // Tim thay gia tri dau tien cua 1 Drum Moi => Bat dau doc cac gia tri
                        string drumSerial = g_xls.ReadCell<string>(iRow++, 2);
                        string cableSerial = g_xls.ReadCell<string>(iRow++, 2);
                        string cableType = g_xls.ReadCell<string>(iRow++, 2);
                        double cableLength = g_xls.ReadCell<double>(iRow++, 2);
                        int cableRuns = g_xls.ReadCell<int>(iRow++, 2);
                        DateTime lastUpdate = g_xls.ReadCell<DateTime>(iRow, 2);
                        CableDrum drum = new CableDrum(drumSerial, cableSerial, cableType, cableLength, cableRuns, lastUpdate);
                        list.Add(drum);
                        // Doc hoan tat, iRow luc nay bang Row dong cuoi cung cua 1 Drum (Last Update)
                    }
                }
            }
            if (closethen) g_xls.CloseBook();
            return list;
        }

        private List<ShipTo> ReadShip2s(bool closethen = true)
        {
            //if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            //g_xls.InitBook(FullPath, "ShipTo", false); // If book already open then Init Sheet only

            List<ShipTo> list = new List<ShipTo>();
            g_xls.ActivateSheet("ShipTo");
            int iRow = 0, iBlank = 0; // Init
            while (iBlank < 5) // Khi nao Blank tren 5 row lien tiep thi Quit Loop
            {
                if (g_xls.IsBlankCell(++iRow, 1)) iBlank++;
                else
                {
                    iBlank = 0; // Neu co chu thi Reset iBlank bat dau dem lai
                    string number = g_xls.ReadCell<string>(iRow, 1); // Read Ship2 No.
                    if (Regex.IsMatch(number, "[0-9]"))
                    {   // Tim thay dung Row ShipTo Number roi day => Bat dau doc gia tri ShipTo Number
                        ShipTo ship2 = new ShipTo(g_xls.ReadCell<string>(iRow, 2), number);
                        // Hoan chinh doc cac thong so cho 1 ShipTo => Add tat ca vao List
                        list.Add(ship2);
                    }
                    // Doc hoan tat, iRow luc nay co gia tri bang gia tri cua ShipTo vua doc.
                }
            }
            if (closethen) g_xls.CloseBook();
            return list;
        }

        private List<Ticket> ReadTickets(bool closethen = true)
        {
            //if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            //g_xls.InitBook(FullPath, "Ticket", false); // If book already open then Init Sheet only

            List<Ticket> list = new List<Ticket>();
            g_xls.ActivateSheet("Ticket");
            int iRow = 0, iBlank = 0; // Init
            while (iBlank < 5) // Khi nao Blank tren 5 row lien tiep thi Quit Loop
            {
                if (g_xls.IsBlankCell(++iRow, 1)) iBlank++;
                else
                {
                    iBlank = 0; // Neu co chu thi Reset iBlank bat dau dem lai
                    string number = g_xls.ReadCell<string>(iRow, 1); // Read Ticket No.
                    if (Regex.IsMatch(number, "[0-9]"))
                    {   // Tim thay dung Row Ticket Number roi day => Bat dau doc gia tri Ticket Number
                        Ticket ticket = new Ticket(number);
                        int iCol = 1;   // Bien iCol de duyet qua phai doc cac thong so & cac Tool Su Dung.
                        ticket.WellName = g_xls.ReadCell<string>(iRow, ++iCol);
                        ticket.JobType = g_xls.ReadCell<string>(iRow, ++iCol);
                        ticket.OpenDate = g_xls.ReadCell<DateTime>(iRow, ++iCol);
                        ticket.OpenEngineer = g_xls.ReadCell<string>(iRow, ++iCol);
                        ticket.ClosedDate = g_xls.ReadCell<DateTime>(iRow, ++iCol);
                        ticket.ClosedEngineer = g_xls.ReadCell<string>(iRow, ++iCol);
                        ticket.JobMD = g_xls.ReadCell<double>(iRow, ++iCol);
                        ticket.JobTVD = g_xls.ReadCell<double>(iRow, ++iCol);
                        List<string> toolList = new List<string>();
                        while (!g_xls.IsBlankCell(iRow, ++iCol))
                        {   // While Cell not Blank thi doc va add list Tool Used
                            toolList.Add(g_xls.ReadCell<string>(iRow, iCol));
                        }
                        // Hoan chinh doc cac thong so cho 1 Ticket => Add tat ca vao List
                        list.Add(ticket);
                    }
                    // Doc hoan tat, iRow luc nay co gia tri bang gia tri cua Ticket vua doc.
                }
            }
            if (closethen) g_xls.CloseBook();
            return list;
        }

        private List<Well> ReadWells(bool closethen = true)
        {
            //if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            //g_xls.InitBook(FullPath, "WellInfo", false); // If book already open then Init Sheet only

            List<Well> list = new List<Well>();
            g_xls.ActivateSheet("WellInfo");
            int iRow = 0, iBlank = 0; // Init
            while (iBlank < 5) // Khi nao Blank tren 5 row lien tiep thi moi Quit Loop
            {
                if (g_xls.IsBlankCell(++iRow, 1)) iBlank++; // Neu trong thi cu tiep tuc tang iBlank thoi
                else
                {   // Neu co chu thi Reset iBlank lai tu dau. Kiem tra WellName bat dau mot Well moi.
                    iBlank = 0;
                    string wellname = g_xls.ReadCell<string>(iRow, 1); // O day khong tang iRow nua
                    if (Regex.IsMatch(wellname, "well.*name", RegexOptions.IgnoreCase)) // Found WellName
                    {   // Da tim thay dong bat dau cua 1 Well moi
                        Well well = new Well(g_xls.ReadCell<string>(iRow, 2)); // Well Name khong can tang Row
                        well.Rig_Platform = g_xls.ReadCell<string>(++iRow, 2);
                        well.Field = g_xls.ReadCell<string>(++iRow, 2);
                        well.HoleType = g_xls.ReadCell<string>(++iRow, 2);
                        well.DrillDepth = g_xls.ReadCell<double>(++iRow, 2);
                        well.LastHUD = g_xls.ReadCell<double>(++iRow, 2);
                        well.TubingSize = g_xls.ReadCell<double>(++iRow, 2); well.TubingShoe = g_xls.ReadCell<double>(iRow, 4);
                        well.CasingSize = g_xls.ReadCell<double>(++iRow, 2); well.CasingShoe = g_xls.ReadCell<double>(iRow, 4);
                        well.EstimatedTOC = g_xls.ReadCell<double>(++iRow, 2);
                        well.CBL_TOC = g_xls.ReadCell<double>(++iRow, 2);
                        well.MaxBHT = g_xls.ReadCell<double>(++iRow, 2);
                        well.WHP = g_xls.ReadCell<double>(++iRow, 2);
                        well.WellFluid = g_xls.ReadCell<string>(++iRow, 2); well.FluidChangeDepth = g_xls.ReadCell<double>(iRow, 4);
                        well.Gravity = g_xls.ReadCell<string>(++iRow, 2);
                        well.FluidLevel = g_xls.ReadCell<double>(++iRow, 2);
                        well.BitSize = g_xls.ReadCell<double>(++iRow, 2);
                        well.MinID = g_xls.ReadCell<double>(++iRow, 2); well.MinID_Depth = g_xls.ReadCell<double>(iRow, 4);
                        well.MaxDEV = g_xls.ReadCell<double>(++iRow, 2); well.MaxDEV_Depth = g_xls.ReadCell<double>(iRow, 4);
                        well.KOP = g_xls.ReadCell<double>(++iRow, 2); well.KOP_Depth = g_xls.ReadCell<double>(iRow, 4);
                        well.MaxDLR = g_xls.ReadCell<double>(++iRow, 2); well.MaxDLR_Depth = g_xls.ReadCell<double>(iRow, 4);
                        well.DevTD = g_xls.ReadCell<double>(++iRow, 2);
                        well.DirTD = g_xls.ReadCell<double>(++iRow, 2);
                        well.GammaLogName = g_xls.ReadCell<string>(++iRow, 2);
                        well.GammaLogDate = g_xls.ReadCell<DateTime>(++iRow, 2);
                        well.CCLLogName = g_xls.ReadCell<string>(++iRow, 2);
                        well.CCLLogDate = g_xls.ReadCell<DateTime>(++iRow, 2);
                        well.LastUpdate = g_xls.ReadCell<DateTime>(++iRow, 2);

                        // IMPLEMENT READ SHIPTO
                        if (ShipTos != null)
                        {
                            int duplicate = -1;
                            foreach (ShipTo ship2 in ShipTos)
                            {
                                if (ship2.WellName.Replace(" ", "").ToLower() == well.Name.Replace(" ", "").ToLower())
                                {
                                    well.ShipTo = ship2.Ship2Number;
                                    duplicate++;
                                }
                            }
                            if (duplicate < 0) PopUp.PopUpOK.ShowDialog("Check your \"Config File\", No ShipTo for this Well in \"ShipTo\" worksheet",
                                string.Format("NO SHIPTO for WELL : \"{0}\"", well.Name));
                            else if (duplicate > 0) PopUp.PopUpOK.ShowDialog("Check your \"Config File\", Duplicate WellName in \"ShipTo\" worksheet");
                        }
                        else PopUp.PopUpOK.ShowDialog("Have to read ShipTo Sheet first !:", "CALL METHOD ORDER ERROR!");
                        // Hoan chinh doc 1 Well => Add Well nay vao List
                        list.Add(well);
                    }
                    // Doc va Add Hoan Tat 1 Well, iRow luc nay phai nam o dong cuoi cung cua Well Vua Doc (Last Update)
                }
            }
            if (closethen) g_xls.CloseBook();
            return list;
        }

        /// <summary>
        /// NOT IMPLEMENT YET
        /// </summary>
        /// <param name="closethen"></param>
        /// <returns></returns>
        private List<ELUnit> ReadELUnits(bool closethen = true)
        {
            //if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            //g_xls.InitBook(FullPath, "UnitCH", false); // If book already open then Init Sheet only

            List<ELUnit> list = new List<ELUnit>();
            g_xls.ActivateSheet("UnitCH");
            //MORE CODE HERE ............................

            return list;
        }

        private List<JobType> ReadJobTypes(bool closethen = true)
        {
            //if (g_xls == null) g_xls = new OfficeLib.Excel(); // Have to check if null then create new otherwise no need
            //g_xls.InitBook(FullPath, "JobType", false); // If book already open then Init Sheet only

            List<JobType> list = new List<JobType>();
            g_xls.ActivateSheet("JobType");
            int iRow = 0, iBlank = 0; // Init
            while (iBlank < 5) // Khi nao Blank tren 5 row lien tiep thi Quit Loop
            {
                if (g_xls.IsBlankCell(++iRow, 1)) iBlank++; // Neu Blank thi tang iBlank
                else
                {
                    iBlank = 0; // Neu co chu thi Reset iBlank bat dau dem lai
                    string name = g_xls.ReadCell<string>(iRow, 1); // Read Unit No.
                    if (!Regex.IsMatch(name, "job.*type", RegexOptions.IgnoreCase))
                    {   // Khong phai la tieu de thi doc job type
                        string shortName = g_xls.ReadCell<string>(iRow, 1);
                        string farpacName = g_xls.ReadCell<string>(iRow, 2);
                        // Hoan chinh doc cac thong so cho 1 JobType => Add tat ca vao List
                        JobType jobtype = new JobType(shortName, farpacName);
                        list.Add(jobtype);
                    }
                    // Doc hoan tat, iRow luc nay co gia tri bang gia tri cua Ticket vua doc.
                }
            }
            if (closethen) g_xls.CloseBook();
            return list;
        }
        #endregion

        //==========================================================//

        #region VARIABLE & PROPERTY
        private OfficeLib.Excel g_xls = null;
        private Dictionary<Paths, string> g_PathDict;
        private Dictionary<Paths, string> g_PathPatternDict;

        //private Paths[] pathsFile;
        //private Paths[] pathsFolder;
        //public Paths[] PathsFile { get { return pathsFile; } }
        //public Paths[] PathsFolder { get { return pathsFolder; } }

        public string FullPath { get; private set; }
        public List<CableDrum> CableDrums { get; private set; }
        public List<Ticket> Tickets { get; private set; }
        public List<ShipTo> ShipTos { get; private set; }
        public List<ELUnit> ELineUnits { get; private set; }
        public List<JobType> JobTypes { get; private set; }
        public List<Well> Wells { get; private set; }
        #endregion

        #region INSTANCE METHOD
        public string this[Paths PathType]
        {
            get { return g_PathDict[PathType]; }
            set { if (PathWrite(PathType, value)) g_PathDict[PathType] = value; }
        }

        /// <summary>
        /// Update a lot of Value at once to save times of Open & Close Config File
        /// </summary>
        public void PathsUpdate(Dictionary<Paths, string> updateDict)
        {
            // Write to Config File at once
            Dictionary<Paths, bool> res = PathWrite(updateDict.Keys.ToArray(), updateDict.Values.ToArray());
            // Update g_PathDict
            foreach (Paths path in updateDict.Keys)
            {
                if (res[path]) g_PathDict[path] = updateDict[path]; // If write to config file success then Update g_PathDict
            }
        }

        /// <summary>
        /// /// Reread the config.xlsx to Update all Path if changed. Normally call this in a timer check | Or before you call Read|Write|PatternPath many time. So use Read Indirect to save time.
        /// </summary>
        public void PathPatternsUpdate() { }
        public void Paths_n_PatternsUpdate() { }

        public Paths EnumFileFolderPath(string FileOrFolderPath)
        {
            if (System.IO.File.Exists(FileOrFolderPath))
            {   // File Path
                string fName = System.IO.Path.GetFileName(FileOrFolderPath).ToLower();
                // Compare with All File Pattern
                foreach (Paths fpath in Configuration.PathsFile)
                {
                    if (Regex.IsMatch(fName, g_PathPatternDict[fpath])) return fpath;
                }
            }
            else if (System.IO.Directory.Exists(FileOrFolderPath))
            {   // Folder Path
                string fName = System.IO.Path.GetDirectoryName(FileOrFolderPath).ToLower();
                // Compare with All Folder Pattern
                foreach (Paths fpath in Configuration.PathsFolder)
                {
                    if (Regex.IsMatch(fName, g_PathPatternDict[fpath])) return fpath;
                }
            }
            // Else for ALL
            return Paths.NA;
        }

        public Paths EnumFolderPaths(string FolderPath)
        {
            if (System.IO.Directory.Exists(FolderPath))
            {   // Folder Path
                string fName = System.IO.Path.GetFileName(FolderPath).ToLower();
                // Compare with All Folder Pattern
                foreach (Paths fpath in Configuration.PathsFolder)
                {
                    if (Regex.IsMatch(fName, g_PathPatternDict[fpath])) return fpath;
                }
            }
            // Else for ALL
            return Paths.NA;
        }

        public Paths EnumFilePaths(string FilePath)
        {
            if (System.IO.File.Exists(FilePath))
            {   // File Path
                string fName = System.IO.Path.GetDirectoryName(FilePath).ToLower();
                // Compare with All File Pattern
                foreach (Paths fpath in Configuration.PathsFile)
                {
                    if (Regex.IsMatch(fName, g_PathPatternDict[fpath])) return fpath;
                }
            }
            // Else for ALL
            return Paths.NA;
        }

        public string GetPath(Paths path) { return g_PathDict[path]; }

        public bool SetPath(Paths path, string value) { bool b = PathWrite(path, value); if (b) g_PathDict[path] = value; return b; }

        public string GetPathPattern(Paths path) { return g_PathPatternDict[path]; }

        public bool SetPathPattern(Paths path, string value) { bool b = PathPatternWrite(path, value); if (b) g_PathPatternDict[path] = value; return b; }
        #endregion

        /// <summary>
        /// Constructor for Config file init inside DemoSummitWPF (only need ShipTos) will set full = false (or by default no need this parameter)
        /// </summary>
        /// <param name="configPath"></param>
        public Configuration(string configPath, bool full = false)
        {
            //pathsFile = GetFilePathsCollection(); pathsFolder = GetFolderPathsCollection(); // Init for File Path & Folder Path Collection. Actually User can call Static Function instead.
            FullPath = configPath;
            using (g_xls) // If exception happen still call Dispose to release resource. No need using g_xls in other function that can return value
            {
                if (g_xls == null) g_xls = new OfficeLib.Excel(); // Check to make sure incase another call to create g_xls again inside this call. Consider to use "using"
                g_xls.InitBook(FullPath, "", true);

                if (full)
                {   // For HalReportWPF
                    ReadPaths_n_Patterns(false);
                    CableDrums = ReadCableDrums(false);
                    Tickets = ReadTickets(false);
                    ShipTos = ReadShip2s(false);
                    JobTypes = ReadJobTypes(false);
                    Wells = ReadWells(false);
                    //ELineUnits = ReadELUnits();
                }
                else
                {   // For DemoSummitWPF
                    ReadPaths_n_Patterns(false);
                    ShipTos = ReadShip2s(false);
                }

                g_xls.CloseBook();
                g_xls = null;
            }
        }

        /// <summary>
        /// FOR TESTING purpose only (CREATE INSTANCE without configPath)
        /// </summary>
        private Configuration() { }
    }
}
